"""
基于用户行为的个性化检索器完整示例
带有模拟数据和详细注释的学习版本
"""

from langchain_core.retrievers import BaseRetriever
from langchain_core.documents import Document
from langchain_core.embeddings import Embeddings
from typing import List, Dict, Any, Optional
import numpy as np
from datetime import datetime, timedelta
import json

from pydantic import Field


class UserBehavior:
    """
    用户行为数据类
    用于记录和分析用户的历史行为
    """

    def __init__(self, user_id: str):
        self.user_id = user_id
        self.view_history = []  # 浏览历史
        self.like_history = []  # 点赞历史
        self.search_history = []  # 搜索历史
        self.dwell_time = {}  # 页面停留时间 {doc_id: seconds}

    def record_view(self, doc_id: str, duration: int = 60):
        """记录用户浏览文档"""
        view_event = {
            "doc_id": doc_id,
            "timestamp": datetime.now(),
            "duration": duration
        }
        self.view_history.append(view_event)

        # 更新停留时间
        self.dwell_time[doc_id] = self.dwell_time.get(doc_id, 0) + duration

    def record_like(self, doc_id: str):
        """记录用户点赞文档"""
        like_event = {
            "doc_id": doc_id,
            "timestamp": datetime.now()
        }
        self.like_history.append(like_event)

    def record_search(self, query: str, clicked_docs: List[str]):
        """记录用户搜索行为"""
        search_event = {
            "query": query,
            "clicked_docs": clicked_docs,
            "timestamp": datetime.now()
        }
        self.search_history.append(search_event)

    def get_preferred_categories(self) -> List[str]:
        """分析用户偏好的文档类别"""
        category_counts = {}

        # 从浏览历史分析
        for view in self.view_history:
            doc_id = view["doc_id"]
            # 在实际应用中，这里需要从文档库获取文档的类别信息
            # 这里我们假设文档ID包含类别信息，如 "tech_doc_1"
            category = doc_id.split('_')[0] if '_' in doc_id else "general"
            duration = view["duration"]

            # 停留时间越长，权重越高
            category_counts[category] = category_counts.get(category, 0) + duration

        # 从点赞历史分析（点赞权重更高）
        for like in self.like_history:
            doc_id = like["doc_id"]
            category = doc_id.split('_')[0] if '_' in doc_id else "general"
            category_counts[category] = category_counts.get(category, 0) + 300  # 点赞相当于5分钟浏览

        # 返回偏好度最高的3个类别
        preferred = sorted(category_counts.items(), key=lambda x: x[1], reverse=True)[:3]
        return [category for category, score in preferred]

    def get_preferred_topics(self) -> List[str]:
        """分析用户感兴趣的主题关键词"""
        # 在实际应用中，这里可以使用NLP技术分析用户历史行为中的主题
        # 这里简化实现，返回一些示例主题
        topics = set()

        # 从搜索历史提取关键词
        for search in self.search_history:
            query = search["query"]
            # 简单的关键词提取（实际应该用更复杂的方法）
            words = query.replace("?", "").replace("什么是", "").split()
            topics.update(words)

        return list(topics)[:5]  # 返回最多5个主题

    def get_recent_interests(self, days: int = 7) -> List[str]:
        """获取用户近期关注的主题"""
        recent_topics = set()
        cutoff_time = datetime.now() - timedelta(days=days)

        for search in self.search_history:
            if search["timestamp"] > cutoff_time:
                query = search["query"]
                words = query.replace("?", "").replace("什么是", "").split()
                recent_topics.update(words)

        return list(recent_topics)


class PersonalizedRetriever(BaseRetriever):
    """
    基于用户行为的个性化检索器

    工作原理：
    1. 先用基础检索器找到相关文档
    2. 根据用户历史行为重新排序文档
    3. 优先展示用户可能感兴趣的文档
    """

    base_retriever: BaseRetriever = Field(...) #   Ellipsis（省略号） 这个字段是必填的,没有默认值   age: int = Field(None, description="用户年龄")  # 可选字段，默认None
    user_behavior: "UserBehavior" = Field(...)
    personalization_strength: float = Field(default=0.7)

    def get_relevant_documents(self, query: str) -> List[Document]:
        """
        核心方法：获取个性化排序的相关文档
        """
        print(f"🔍 用户 '{self.user_behavior.user_id}' 查询: '{query}'")

        # 步骤1: 使用基础检索器获取相关文档
        base_docs = self.base_retriever.get_relevant_documents(query)
        print(f"   基础检索找到 {len(base_docs)} 个相关文档")

        if not base_docs:
            return []

        # 步骤2: 计算每个文档的个性化分数
        scored_docs = []
        for doc in base_docs:
            base_score = 1.0  # 基础相关性分数（简化处理）

            # 计算个性化分数
            personalization_score = self._calculate_personalization_score(doc)

            # 综合分数 = 基础分数 + 个性化调整
            total_score = (1 - self.personalization_strength) * base_score + \
                          self.personalization_strength * personalization_score

            scored_docs.append((total_score, doc))

            # 打印调试信息
            doc_id = doc.metadata.get("doc_id", "unknown")
            print(f"   文档 '{doc_id}': 基础分={base_score:.2f}, 个性化分={personalization_score:.2f}, 总分={total_score:.2f}")

        # 步骤3: 按综合分数排序
        scored_docs.sort(key=lambda x: x[0], reverse=True)

        # 步骤4: 返回重新排序的文档
        final_docs = [doc for score, doc in scored_docs]

        print(f"✅ 个性化排序完成，返回 {len(final_docs)} 个文档")
        return final_docs

    def _calculate_personalization_score(self, doc: Document) -> float:
        """
        计算文档的个性化分数
        基于用户历史行为判断用户对这个文档的兴趣程度
        """
        score = 0.0
        doc_id = doc.metadata.get("doc_id", "")
        doc_category = doc.metadata.get("category", "general")
        doc_content = doc.page_content.lower()

        # 1. 基于类别的偏好
        preferred_categories = self.user_behavior.get_preferred_categories()
        if doc_category in preferred_categories:
            category_rank = preferred_categories.index(doc_category)
            # 排名越靠前，分数越高
            score += (len(preferred_categories) - category_rank) * 0.3

        # 2. 基于主题关键词的匹配
        preferred_topics = self.user_behavior.get_preferred_topics()
        for topic in preferred_topics:
            if topic.lower() in doc_content:
                score += 0.2  # 每个匹配的关键词加0.2分

        # 3. 基于近期兴趣的匹配
        recent_interests = self.user_behavior.get_recent_interests()
        for interest in recent_interests:
            if interest.lower() in doc_content:
                score += 0.3  # 近期兴趣权重更高

        # 4. 基于历史交互行为
        # 检查用户是否之前浏览过这个文档
        for view in self.user_behavior.view_history:
            if view["doc_id"] == doc_id:
                # 基于停留时间计算分数（停留时间越长，兴趣越大）
                dwell_time = view["duration"]
                score += min(dwell_time / 300, 1.0)  # 最大1分，5分钟为上限

        # 检查用户是否点赞过这个文档
        for like in self.user_behavior.like_history:
            if like["doc_id"] == doc_id:
                score += 2.0  # 点赞表示强烈兴趣

        # 5. 确保分数在合理范围内
        return min(score, 5.0)  # 最大5分

    async def aget_relevant_documents(self, query: str) -> List[Document]:
        """异步版本"""
        return self.get_relevant_documents(query)


# 🎯 演示代码
def create_sample_documents() -> List[Document]:
    """创建示例文档库"""
    return [
        Document(
            page_content="Python 是一种高级编程语言，以其简洁的语法和强大的库而闻名。",
            metadata={"doc_id": "programming_python_1", "category": "programming", "difficulty": "beginner"}
        ),
        Document(
            page_content="机器学习是人工智能的一个分支，专注于让计算机从数据中学习。",
            metadata={"doc_id": "ai_ml_1", "category": "ai", "difficulty": "intermediate"}
        ),
        Document(
            page_content="深度学习使用神经网络模拟人脑的工作方式，用于图像识别和自然语言处理。",
            metadata={"doc_id": "ai_dl_1", "category": "ai", "difficulty": "advanced"}
        ),
        Document(
            page_content="JavaScript 是用于网页开发的脚本语言，可以为网站添加交互功能。",
            metadata={"doc_id": "web_js_1", "category": "web", "difficulty": "beginner"}
        ),
        Document(
            page_content="React 是一个用于构建用户界面的 JavaScript 库，由 Facebook 开发。",
            metadata={"doc_id": "web_react_1", "category": "web", "difficulty": "intermediate"}
        ),
        Document(
            page_content="TensorFlow 是 Google 开发的机器学习框架，广泛用于深度学习项目。",
            metadata={"doc_id": "ai_tensorflow_1", "category": "ai", "difficulty": "advanced"}
        ),
        Document(
            page_content="Docker 是一个容器化平台，可以帮助开发者打包和部署应用程序。",
            metadata={"doc_id": "devops_docker_1", "category": "devops", "difficulty": "intermediate"}
        ),
        Document(
            page_content="Kubernetes 是一个容器编排系统，用于自动化部署、扩展和管理容器化应用。",
            metadata={"doc_id": "devops_k8s_1", "category": "devops", "difficulty": "advanced"}
        )
    ]


def create_base_retriever(documents: List[Document]) -> BaseRetriever:
    """创建基础检索器（简化版本）"""
    from langchain_chroma import Chroma
    from langchain_huggingface import HuggingFaceEmbeddings

    # 使用简单的嵌入模型（实际使用时需要正确配置）
    class SimpleEmbeddings(Embeddings):
        def embed_documents(self, texts: List[str]) -> List[List[float]]:
            # 简化实现，实际应该使用真实的嵌入模型
            return [[0.1] * 384 for _ in texts]

        def embed_query(self, text: str) -> List[float]:
            return [0.1] * 384

    embeddings = SimpleEmbeddings()
    vectorstore = Chroma.from_documents(documents, embeddings)

    return vectorstore.as_retriever(search_kwargs={"k": 10})


def simulate_user_behavior(user_behavior: UserBehavior):
    """模拟用户行为数据"""
    print("🎭 模拟用户行为数据...")

    # 模拟用户浏览行为
    user_behavior.record_view("ai_ml_1", duration=120)  # 浏览机器学习文档2分钟
    user_behavior.record_view("ai_dl_1", duration=180)  # 浏览深度学习文档3分钟
    user_behavior.record_view("programming_python_1", duration=60)  # 浏览Python文档1分钟

    # 模拟用户点赞行为
    user_behavior.record_like("ai_ml_1")  # 点赞机器学习文档
    user_behavior.record_like("ai_tensorflow_1")  # 点赞TensorFlow文档

    # 模拟用户搜索行为
    user_behavior.record_search("什么是机器学习", ["ai_ml_1", "ai_dl_1"])
    user_behavior.record_search("Python 编程基础", ["programming_python_1"])
    user_behavior.record_search("深度学习框架", ["ai_tensorflow_1"])

    print("✅ 用户行为数据模拟完成")


def main():
    """主演示函数"""
    print("🚀 基于用户行为的个性化检索器演示")
    print("=" * 60)

    # 1. 创建文档库
    documents = create_sample_documents()
    print(f"📚 创建了 {len(documents)} 个示例文档")

    # 2. 创建基础检索器
    base_retriever = create_base_retriever(documents)
    print("✅ 基础检索器创建完成")

    # 3. 创建用户行为数据
    user_behavior = UserBehavior("user_001")
    simulate_user_behavior(user_behavior)

    # 4. 分析用户偏好
    print(f"\n📊 用户偏好分析:")
    print(f"   偏好类别: {user_behavior.get_preferred_categories()}")
    print(f"   兴趣主题: {user_behavior.get_preferred_topics()}")
    print(f"   近期关注: {user_behavior.get_recent_interests()}")

    # 5. 创建个性化检索器
    personalized_retriever = PersonalizedRetriever(
        base_retriever=base_retriever,
        user_behavior=user_behavior,
        personalization_strength=0.7  # 70% 个性化强度
    )

    # 6. 测试查询
    test_queries = [
        "编程语言学习",
        "人工智能技术",
        "开发工具"
    ]

    for query in test_queries:
        print(f"\n🎯 测试查询: '{query}'")
        print("-" * 50)

        results = personalized_retriever.get_relevant_documents(query)

        print(f"📄 个性化推荐结果:")
        for i, doc in enumerate(results[:3]):  # 只显示前3个
            doc_id = doc.metadata.get("doc_id", "unknown")
            category = doc.metadata.get("category", "unknown")
            print(f"   {i + 1}. [{category}] {doc.page_content[:50]}...")

    # 7. 对比个性化 vs 非个性化
    print(f"\n🔍 个性化效果对比:")
    print("=" * 60)

    query = "学习编程"
    print(f"查询: '{query}'")

    # 非个性化结果
    print("\n📋 非个性化结果:")
    base_results = base_retriever.get_relevant_documents(query)
    for i, doc in enumerate(base_results[:3]):
        category = doc.metadata.get("category", "unknown")
        print(f"   {i + 1}. [{category}] {doc.page_content[:40]}...")

    # 个性化结果
    print("\n❤️  个性化结果:")
    personal_results = personalized_retriever.get_relevant_documents(query)
    for i, doc in enumerate(personal_results[:3]):
        category = doc.metadata.get("category", "unknown")
        print(f"   {i + 1}. [{category}] {doc.page_content[:40]}...")


if __name__ == "__main__":
    main()